#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>

namespace BlockQueueModule
{
    template <class T>
    class BlockQueue
    {
    private:
        // 阻塞队列
        std::queue<T> _block_queue;
        // 容量
        int _cap;
        // 保护queue的锁
        pthread_mutex_t _mutex;
        // 生产/消费者用条件变量
        pthread_cond_t _productor_cond;
        pthread_cond_t _consumer_cond;
        // 等待数
        int _productor_wait_num;
        int _consumer_wait_num;

        bool Isfull() { return _block_queue.size() == _cap; }
        bool Isempty() { return _block_queue.empty(); }

    public:
        BlockQueue(int cap)
            : _cap(cap), _productor_wait_num(0), _consumer_wait_num(0)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_productor_cond, nullptr);
            pthread_cond_init(&_consumer_cond, nullptr);
        }

        ~BlockQueue()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_productor_cond);
            pthread_cond_destroy(&_consumer_cond);
        }
        // 生产
        void Enqueue(const T& in)
        {
            // 加锁
            pthread_mutex_lock(&_mutex);
            // 当队列满时等待
            while (Isfull())
            {
                ++_productor_wait_num;
                pthread_cond_wait(&_productor_cond, &_mutex);
                //std::cout << "_productor_wait_num:" << _productor_wait_num << std::endl;
                // 被唤醒,重新获得锁
                --_productor_wait_num;
            }
            _block_queue.push(in);
            // 唤醒等待的消费者
            if (_consumer_wait_num)
                pthread_cond_signal(&_consumer_cond);
            pthread_mutex_unlock(&_mutex);
        }

        // 消费
        void Pop(T* out) // 输出型参数
        {
            // 加锁
            pthread_mutex_lock(&_mutex);
            // 队列为空则等待
            while (Isempty())
            {
                ++_consumer_wait_num;
                pthread_cond_wait(&_consumer_cond, &_mutex);
                //std::cout << "_consumer_wait_num:" << _consumer_wait_num << std::endl;
                // 被唤醒并重新得到锁
                --_consumer_wait_num;
            }
            // 消费
            *out = _block_queue.front();
            _block_queue.pop();
            // 唤醒等待的生产者
            if (_productor_wait_num)
                pthread_cond_signal(&_productor_cond);
            pthread_mutex_unlock(&_mutex);
        }
    };
}